/**
 * @file LogFile.cpp
 * @brief 日志文件管理实现
 * @author Enterprise Logger Team
 * @date 2024
 */

#include "LogFile.h"
#include <cassert>
#include <cstdio>
#include <ctime>
#include <sstream>
#include <iomanip>
#include <chrono>

namespace logger {

// FileUtil实现
FileUtil::FileUtil(const std::string& filename)
    : file_(filename, std::ios::out | std::ios::app | std::ios::binary),
      writtenBytes_(0) {
    
    // 设置缓冲区
    if (file_.is_open()) {
        file_.rdbuf()->pubsetbuf(buffer_, sizeof(buffer_));
    }
}

FileUtil::~FileUtil() {
    if (file_.is_open()) {
        file_.close();
    }
}

void FileUtil::append(const char* logline, size_t len) {
    if (file_.is_open()) {
        size_t written = write(logline, len);
        writtenBytes_ += written;
    }
}

void FileUtil::flush() {
    if (file_.is_open()) {
        file_.flush();
    }
}

size_t FileUtil::write(const char* logline, size_t len) {
    if (file_.is_open()) {
        file_.write(logline, len);
        return file_.good() ? len : 0;
    }
    return 0;
}

// LogFile实现
LogFile::LogFile(const std::string& basename,
                 size_t rollSize,
                 bool threadSafe,
                 int flushInterval,
                 int checkEveryN)
    : basename_(basename),
      rollSize_(rollSize),
      flushInterval_(flushInterval),
      checkEveryN_(checkEveryN),
      count_(0),
      mutex_(threadSafe ? new std::mutex : nullptr),
      writtenBytes_(0),
      startOfPeriod_(0),
      lastRoll_(0),
      lastFlush_(0) {
    
    rollFile();
}

LogFile::~LogFile() = default;

void LogFile::append(const char* logline, int len) {
    if (mutex_) {
        std::lock_guard<std::mutex> lock(*mutex_);
        append_unlocked(logline, len);
    } else {
        append_unlocked(logline, len);
    }
}

void LogFile::flush() {
    if (mutex_) {
        std::lock_guard<std::mutex> lock(*mutex_);
        if (file_) {
            file_->flush();
        }
    } else {
        if (file_) {
            file_->flush();
        }
    }
    lastFlush_ = time(nullptr);
}

void LogFile::append_unlocked(const char* logline, int len) {
    if (file_) {
        file_->append(logline, len);
    }
    writtenBytes_ += len;
    
    // 检查是否需要滚动
    if (writtenBytes_ > rollSize_) {
        rollFile();
    } else {
        ++count_;
        if (count_ >= checkEveryN_) {
            count_ = 0;
            time_t now = time(nullptr);
            time_t thisPeriod = now / kRollPerSeconds_ * kRollPerSeconds_;
            
            // 检查是否跨天
            if (thisPeriod != startOfPeriod_) {
                rollFile();
            } else if (now - lastFlush_ > flushInterval_) {
                // 定期刷新
                file_->flush();
                lastFlush_ = now;
            }
        }
    }
}

bool LogFile::rollFile() {
    time_t now = 0;
    std::string filename = getLogFileName(basename_, &now);
    
    // 计算下一天的起始时间
    time_t start = now / kRollPerSeconds_ * kRollPerSeconds_;
    
    // 避免在同一秒内重复滚动
    if (now > lastRoll_) {
        lastRoll_ = now;
        lastFlush_ = now;
        startOfPeriod_ = start;
        
        // 创建新文件
        file_.reset(new FileUtil(filename));
        writtenBytes_ = 0;
        return true;
    }
    return false;
}

std::string LogFile::getLogFileName(const std::string& basename, time_t* now) {
    std::string filename;
    filename.reserve(basename.size() + 64);
    filename = basename;
    
    // 获取当前时间
    auto now_time = std::chrono::system_clock::now();
    auto now_c = std::chrono::system_clock::to_time_t(now_time);
    *now = now_c;
    
    // 获取毫秒
    auto now_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
        now_time.time_since_epoch()) % 1000;
    
    // 格式化时间
    struct tm tm_now;
#ifdef _WIN32
    localtime_s(&tm_now, &now_c);
#else
    localtime_r(&now_c, &tm_now);
#endif
    
    // 构建文件名：basename-YYYYMMDD-HHMMSS-mmm.log
    char timebuf[64];
    snprintf(timebuf, sizeof(timebuf),
             "-%04d%02d%02d-%02d%02d%02d-%03lld.log",
             tm_now.tm_year + 1900,
             tm_now.tm_mon + 1,
             tm_now.tm_mday,
             tm_now.tm_hour,
             tm_now.tm_min,
             tm_now.tm_sec,
             static_cast<long long>(now_ms.count()));
    
    filename += timebuf;
    
    return filename;
}



}  // namespace logger
